/*
 * GUID.java
 *
 * Created on September 10, 2006, 12:50 PM
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */

package edu.byu.isys413.group1E;
import java.net.*;
import java.util.*;

/**
 *  Generates globally-unique identifiers
 *
 *  @author Travis Kulbeth, <tkulbeth@gmail.com>, ISys 403, Section 1
 *  @version 1.0
 */
public class GUID {
    //global variables to track creation times and number of instances
    private static long prevTime = 0;
    private static long counter = 0;
    
    
    /**
     *Constructor for GUID class, does nothing
     *
     *@returns nothing
     */
    private GUID() {
    }
    
    
    /**
     *Generates a pad of zeros to fill in a character limit for a hexadecimal value
     *
     *@returns a String containing the new hex number with the needed number of zeros
     */
    private static String addZeros(int diff, String hexStr){
        
        char addHexTime[] = new char[diff];
        
        for (int indx=0; indx<diff; indx++){                          //create a character array of needed zeros
            addHexTime[indx] = '0';
        }
        
        String newZeros = new String(addHexTime);
        hexStr = newZeros.concat(hexStr);                             //pad front of string with zeros
        return hexStr;
    }//end method addZeros
    
    
    /**
     *  Generates a new GUID
     *
     *  @return A unique GUID as a String
     */
    public static synchronized String generate() throws Exception {
        String guidNumber = "";
        String hexTime, hexCounter, hexIP = "";
        
        /**
         * Create current time in hexadecimal for GUID
         */
        if (counter == 16777215)                                      //check against the max counter
            Thread.sleep(1);                                          //wait for the next millisecond if necessary
        
        long curTime = System.currentTimeMillis();                    //retrieve current time in milliseconds
        //System.out.println(curTime);
        hexTime = Long.toHexString(curTime);                          //convert time to hex
        int diff = 16 - hexTime.length();                             //determine if the hexadecimal string fits the 16 character length
        
        if(diff > 0){                                                 //add necessary zeros to pad up to 16 characters
            hexTime = addZeros(diff, hexTime);
        }
        
        /**
         *Get counter for multiple GUID's within a millisecond
         */
        if (curTime == prevTime){                                     //Check new time against previous time
            counter++;
        }else{                                                        //if different, set prevTime to curTime and reset counter
            if(prevTime == 0){                                          //check if it's the first use of this instance
                prevTime = curTime;
            }else{
                prevTime = curTime;
                counter = 0;
            }
        }
        hexCounter = Long.toHexString(counter);                       //convert counter to hex
        diff = 6 - hexCounter.length();
        
        if (diff > 0){                                                //add necessary zeros to pad up to 6 characters
            hexCounter = addZeros(diff, hexCounter);
        }
        
        /**
         * Get IP address for GUID
         */
        try {
            InetAddress addr = InetAddress.getLocalHost();           //retrieve InetAddress object and get a byte array of IP address
            byte[] ip = addr.getAddress();
            String[] ipHexStr = new String[4];
            int[] ipInt = new int[4];
            
            for (int i=0;  i<ip.length; i++){                        //convert byte array to an Int array before converting to hex
                if (ip[i] < 0){                                          //check if the byte array contains a negative number, and fix it
                    ipInt[i] = 256 + ip[i];
                }else{
                    ipInt[i] = ip[i];
                }
                
                ipHexStr[i] = Integer.toHexString(ipInt[i]);         //convert to hex
                diff = 2 - ipHexStr[i].length();
                
                if(diff > 0){
                    ipHexStr[i] = addZeros(diff, ipHexStr[i]);          //add needed zeros to have 2 characters per hex figure
                }
                hexIP = hexIP.concat(ipHexStr[i]);                   //add each padded hex IP component to overall hexIP string
            }
        } catch (UnknownHostException e) {}
        
        /**
         *finally, put all the hex values together for result
         */
        guidNumber = hexTime.concat(hexCounter).concat(hexIP);         //build GUID with each component and return
        return guidNumber;
    }//end method generate
    
    
    /**
     *Parses the time value out of the hex GUID and converts it to the date
     *
     *@return the time the GUID was generated
     */
    public static String getTime(String g){
        long gTime = 0;
        String guidTime = "";
        String substr = g.substring(0,16);                            //retrieve the time portion from the GUID
        
        try{
            gTime = Long.parseLong(substr, 16);                       //convert hex time to long
        }catch ( NumberFormatException u) {}
        Date guidDate = new Date(gTime);                              //extract the date from the long number time
        guidTime = guidDate.toString();                               //create String containing the creation date
        
        return guidTime;
    }//end method getTime
    
    
    /**
     *Retrieves the counter value from the hex GUID and converts it to decimal
     *
     *@return the counter indicating how many GUIDs were created within a millisecond
     */
    public static long getCounter(String g){
        long gCount = 0;
        String substr = g.substring(17,22);
        
        try{
            gCount = Long.parseLong(substr,16);                       //retrieve counter segment from GUID
        }catch (NumberFormatException z){}
        
        return gCount;
    }//end method get Counter
    
    
    /**
     *Retrieves the IP address portion of the GUID and converts it to decimal, in an IP String
     *
     *@return a String containing the IP address of the computer where the GUID was created
     */
    public static String getIP(String g){
        long ipSeg[] = new long[4];
        String strIP = "";
        int start = 22, end = 24;
        
        for (int w=0; w<4; w++){
            String substr = g.substring(start,end);                   //retrieve the first part of the IP
            try{
                ipSeg[w] = Long.parseLong(substr, 16);                   //retrieve ip segment from GUID hex
            }catch (NumberFormatException z){}
            strIP = strIP.concat(Long.toString(ipSeg[w]));            //add the IP segment to the result string
            if(w < 3){
                strIP = strIP.concat(".");                            //if there is a dot following the current segment, add it
            }
            start += 2;                                               //increment placement counters by two for the next segment
            end += 2;
        }
        return strIP;
    }//end method get IP
}